﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Configuration;
using Migracion.Process.voz;
using Migracion.Data.ArbolVoces;
using System.Xml.Linq;
using System.IO;
using Migracion.Data.PeOnline;
using System.Web;
using System.Text.RegularExpressions;

namespace Migracion.Process
{
    public class BaseProcess
    {

        public string currentId = string.Empty;
        public int cantidadDeFallosOk = 0;
        protected const char SeparadorDeVocesChar = '-';
        private const string citaStr = "cite";
        private const string citaVerTexto = "Ver Texto";

        public event ProgressStatus OnProgressStatus;

        public event LogStatus OnLogStatus;

        protected void LogStatusMessage(string message, MigracionLogStatus status)
        {
            if (OnLogStatus != null)
            {
                OnLogStatus(currentId, message + Environment.NewLine + " ## Tiempo Acumulado: " + string.Format("{0:D2}:{1:D2}:{2:D2}", watch.Elapsed.Hours, watch.Elapsed.Minutes, watch.Elapsed.Seconds), status);
            }
        }

        public bool EsModoProduccion
        {
            get
            {
                string modo = ConfigurationManager.AppSettings["modoProduccion"];
                return modo == "1";
            }
        }

        protected void ProgressStatus(int actual, int totales)
        {
            if (OnProgressStatus != null)
            {
                OnProgressStatus(actual, totales);
            }
        }

        protected Stopwatch watch = new Stopwatch();

        public IdentityTranslationManager IdTranslationManager { get; set; }

        public LinksManager LinkManager { get; set; }

        protected void InicializarManagers()
        {
            if (IdTranslationManager == null)
            {
                IdTranslationManager = new IdentityTranslationManager();
                IdTranslationManager.modoProduccion = EsModoProduccion;
            }

            if (LinkManager == null)
            {
                LinkManager = new LinksManager();
            }
        }

        public string GetExceptionMessage(Exception ex)
        {
            StringBuilder builder = new StringBuilder();

            Exception current = ex;
            while (current != null)
            {
                builder.Append(current.Message);
                current = current.InnerException;
            }

            return builder.ToString();
        }

        public string GetExceptionStackTrace(Exception ex)
        {
            StringBuilder builder = new StringBuilder();

            Exception current = ex;
            while (current != null)
            {
                builder.Append(current.StackTrace);
                current = current.InnerException;
            }

            return builder.ToString();
        }

        protected static List<MigraVoz> FiltrarPorArbolDeVoces(List<MigraVoz> listadoDeVoces)
        {
            List<MigraVoz> listadoDeVocesFinales = new List<MigraVoz>();

            // Separo las voces que están juntas en voces individuales.
            foreach (MigraVoz migraVoz in listadoDeVoces)
            {

                string[] subVocesStrArray = migraVoz.Nombre.Split(SeparadorDeVocesChar);
                if (subVocesStrArray.Length == 2)
                {
                    // si la voz que queda luego del split es de 4 digitos, la separó mal y en realidad va junta
                    if (subVocesStrArray[0].Length < 5)
                    {
                        subVocesStrArray = new string[] { migraVoz.Nombre };
                    }
                }

                foreach (string s in subVocesStrArray)
                {
                    if (!String.IsNullOrEmpty(s))
                    {
                        MigraVoz nuevaMigraVoz = new MigraVoz();
                        nuevaMigraVoz.Nombre = s.Trim();
                        nuevaMigraVoz.Nivel = migraVoz.Nivel;
                        nuevaMigraVoz.Numero = migraVoz.Numero;
                        nuevaMigraVoz.IdTaxonomia = migraVoz.IdTaxonomia;
                        listadoDeVocesFinales.Add(nuevaMigraVoz);
                    }
                }
            }

            // Una vez que estan unificadas, control cuales están en el arbol de voces
            using (ArbolDeVocesEntities ctxArbolDeVoces = new ArbolDeVocesEntities())
            {
                // Por cada voz me voy metiendo un nivel y viendo qué voz es
                int cantidadDeVoces = listadoDeVocesFinales.Count;
                bool finVoces = false;
                int nivelVoz = 0;
                int idVozPadre = 0;
                int idVoz = 0;
                for (int i = 0; i < cantidadDeVoces && !finVoces; i++)
                {
                    MigraVoz migraVoz = listadoDeVocesFinales[i];
                    migraVoz.Nombre = migraVoz.Nombre;

                    // la primera la analizo en forma independiente
                    if (idVozPadre == 0)
                    {
                        // la voz padre la busco por igual y sino esta la busco por like
                        var query = from v in ctxArbolDeVoces.tVoces
                                    where (from j in ctxArbolDeVoces.tJerarquias
                                           where j.IdVozH == v.IdVoz
                                           select 1).Count() == 0
                                    && v.Descripcion.EndsWith(migraVoz.Nombre)
                                    select v;

                        var vocesList = query.ToList();

                        // si hay mas de una voz trato de buscar la que va
                        if (vocesList.Count > 1)
                        {
                            int idVozMenor = 0;
                            string nombreVozMenor = string.Empty;
                            foreach (var voces in vocesList)
                            {
                                if (voces.Descripcion.ToLower() == migraVoz.Nombre.ToLower())
                                {
                                    idVoz = voces.IdVoz;
                                    break;
                                }
                                else
                                {
                                    // analizo la menor
                                    if (String.IsNullOrEmpty(nombreVozMenor))
                                    {
                                        nombreVozMenor = voces.Descripcion.ToLower();
                                        idVozMenor = voces.IdVoz;
                                    }
                                    else if (voces.Descripcion.Length < nombreVozMenor.Length)
                                    {
                                        nombreVozMenor = voces.Descripcion.ToLower();
                                        idVozMenor = voces.IdVoz;
                                    }

                                }
                            }

                            // si no lo encontro es el menor
                            if (idVoz == 0)
                            {
                                idVoz = idVozMenor;
                            }
                        }
                        else if (vocesList.Count == 1) // si es una uso esa
                        {
                            idVoz = vocesList.First().IdVoz;
                        }
                        // si no esta no hago nada porque no existe la voz
                    }
                    else
                    {
                        // el resto de las voces las analizo asi
                        var vocesList = (from v in ctxArbolDeVoces.tVoces
                                         join j in ctxArbolDeVoces.tJerarquias on v.IdVoz equals j.IdVozH
                                         where j.IdVozP == idVozPadre
                                         && v.Descripcion.EndsWith(migraVoz.Nombre)
                                         select v).ToList();

                        if (vocesList.Count > 1)
                        {
                            int idVozMenor = 0;
                            string nombreVozMenor = string.Empty;
                            foreach (var voces in vocesList)
                            {
                                if (voces.Descripcion.ToLower() == migraVoz.Nombre.ToLower())
                                {
                                    idVoz = voces.IdVoz;
                                    break;
                                }
                                else
                                {
                                    // analizo la menor
                                    if (String.IsNullOrEmpty(nombreVozMenor))
                                    {
                                        nombreVozMenor = voces.Descripcion.ToLower();
                                        idVozMenor = voces.IdVoz;
                                    }
                                    else if (voces.Descripcion.Length < nombreVozMenor.Length)
                                    {
                                        nombreVozMenor = voces.Descripcion.ToLower();
                                        idVozMenor = voces.IdVoz;
                                    }

                                }
                            }

                            // si no lo encontro es el menor
                            if (idVoz == 0)
                            {
                                idVoz = idVozMenor;
                            }
                        }
                        else if (vocesList.Count == 1) // si es una uso esa
                        {
                            idVoz = vocesList.First().IdVoz;
                        }
                    }

                    if (idVoz == 0)
                    {
                        // Si la voz es cero, entonces no existe y salgo del loop
                        finVoces = true;
                    }
                    else
                    {
                        migraVoz.NivelEnArbolDeVoces = nivelVoz;
                        migraVoz.EsVozDelArbolDeVoces = true;
                        idVozPadre = idVoz;
                        idVoz = 0;
                        nivelVoz++;
                    }
                }
            }

            return listadoDeVocesFinales;
        }

        public static string HtmlDecode(string htmlString)
        {
            return HttpUtility.HtmlDecode(htmlString);
        }

        public string ProcesarCuerpo(PE_ONLINE_PRODUCCIONEntities ctxPeOnline, Guid guidDocumentoSae, int IdAP, string cuerpoDelFallo, bool escapearTexto = true, bool usarVerTexto = true)
        {
            if (escapearTexto)
            {
                cuerpoDelFallo = EscapearTexto(cuerpoDelFallo);
            }

            ////cuerpodelfallo = cuerpodelfallo.replace(@"<", "&lt;");
            ////cuerpodelfallo = cuerpodelfallo.replace(@">", "&gt;");
            ////cuerpodelfallo = cuerpodelfallo.replace("\"", "&quot;");
            ////cuerpodelfallo = cuerpodelfallo.replace(@"'", "&apos;");

            cuerpoDelFallo = "<root>" + cuerpoDelFallo + "</root>";


            using (StringReader strReader = new StringReader(cuerpoDelFallo))
            {
                XDocument xCuerpoFallo = XDocument.Load(strReader);

                // proceso posbiles imagenes
                CitasTipoImagen(guidDocumentoSae, IdAP, xCuerpoFallo);

                List<LinkAp> allLinks = new List<LinkAp>();

                // Citas tipo notas al pie
                List<LinkAp> linksApListNotasAlPie = GetCitasTipoNotasAlPie(guidDocumentoSae, IdAP, xCuerpoFallo);

                // Citas tipo Cun
                List<LinkAp> linksApListCUN = GetCitasTipoCun(ctxPeOnline, guidDocumentoSae, IdAP, xCuerpoFallo);

                // Citas tipo ZZ
                List<LinkAp> linksApListZZ = GetCitasTipoObraZZ(ctxPeOnline, guidDocumentoSae, IdAP, xCuerpoFallo);

                // Citas tipo jur
                List<LinkAp> linksApJurisprudenciaList = GetCitasTipoJurisprudencia(ctxPeOnline, guidDocumentoSae, IdAP, xCuerpoFallo);

                // Citas tipo jj_anotada
                List<LinkAp> linksApJurisprudenciaAnotadaList = GetCitasJurisprudenciaAnotada(ctxPeOnline, guidDocumentoSae, IdAP, xCuerpoFallo);

                List<LinkAp> linksApDoctrina = GetCitasTipoDoctrina(ctxPeOnline, guidDocumentoSae, IdAP, xCuerpoFallo);

                allLinks.AddRange(linksApListNotasAlPie);
                allLinks.AddRange(linksApListCUN);
                allLinks.AddRange(linksApListZZ);
                allLinks.AddRange(linksApJurisprudenciaList);
                allLinks.AddRange(linksApJurisprudenciaAnotadaList);
                allLinks.AddRange(linksApDoctrina);

                // Filtro solo los links que apuntan a este documento
                allLinks = allLinks.Where(l => l.GuidDocDestino == l.GuidDocOrigen).ToList();

                // Proceso las anclas del documento
                List<XElement> anclasEnElFallo = (from node in xCuerpoFallo.Descendants()
                                                  where node.Name == "Ancla"
                                                  select node).ToList();

                foreach (var anclaNode in anclasEnElFallo)
                {
                    //<Ancla tipo="link" id="cita8" />
                    // Si el ancla la apuntan desde el mismo documento genero un ancla común de html, sino un cite
                    string aname = anclaNode.Attribute("id").Value;

                    LinkAp link = allLinks.Where(l => l.HrefLinkAnchor == aname).FirstOrDefault();

                    if (link != null)
                    {
                        XElement newAncla2 = new XElement("a", string.Empty);
                        newAncla2.Add(new XAttribute("name", aname));
                        anclaNode.AddAfterSelf(newAncla2);
                    }

                    XElement newAncla = new XElement(citaStr, string.Empty);
                    newAncla.Add(new XAttribute("guid", LinkManager.StoreAnchorForDocument(guidDocumentoSae, IdAP, anclaNode.Attribute("id").Value).ToString()));
                    anclaNode.ReplaceWith(newAncla);
                }

                CitasParaListaDeLinks(linksApListNotasAlPie, usarVerTexto);
                CitasParaListaDeLinks(linksApListCUN, usarVerTexto);
                CitasParaListaDeLinks(linksApListZZ, usarVerTexto);
                CitasParaListaDeLinks(linksApJurisprudenciaList, usarVerTexto);
                CitasParaListaDeLinks(linksApJurisprudenciaAnotadaList, usarVerTexto);
                CitasParaListaDeLinks(linksApDoctrina, usarVerTexto);


                string textoStr = xCuerpoFallo.ToString();
                textoStr = textoStr.Remove(0, 6);
                if (textoStr[0] == '\r' && textoStr[1] == '\n')
                {
                    textoStr = textoStr.Remove(0, 2);
                }

                textoStr = textoStr.Remove(textoStr.Length - 7, 7);

                strReader.Close();

                return textoStr;
            }
        }

        protected static string EscapearTexto(string cuerpoDelFallo)
        {
            if (!String.IsNullOrEmpty(cuerpoDelFallo))
            {
                cuerpoDelFallo = HtmlDecode(cuerpoDelFallo);
                //cuerpoDelFallo = System.Security.SecurityElement.Escape(cuerpoDelFallo);
                cuerpoDelFallo = cuerpoDelFallo.Replace(@"&", "&amp;");
                cuerpoDelFallo = cuerpoDelFallo.Replace(@"<<", "&lt;&lt;");
                cuerpoDelFallo = cuerpoDelFallo.Replace(@">>", "&gt;&gt;");
                //cuerpoDelFallo = cuerpoDelFallo.Replace("<HD+>", "<![CDATA[<HD+>]]>");
                //cuerpoDelFallo = cuerpoDelFallo.Replace("<HD->", "<![CDATA[<HD->]]>");
                //cuerpoDelFallo = cuerpoDelFallo.Replace("<R>", "<![CDATA[<R>]]>");
                cuerpoDelFallo = cuerpoDelFallo.Replace("<HD+>", string.Empty);
                cuerpoDelFallo = cuerpoDelFallo.Replace("<HD->", string.Empty);
                cuerpoDelFallo = cuerpoDelFallo.Replace("<R>", string.Empty);
                cuerpoDelFallo = cuerpoDelFallo.Replace("<P10B>", string.Empty);
                cuerpoDelFallo = cuerpoDelFallo.Replace("<$ICITA>", string.Empty);
                cuerpoDelFallo = cuerpoDelFallo.Replace("<$ICITAFIN>", string.Empty);
                cuerpoDelFallo = cuerpoDelFallo.Replace("<=>", "&lt;=&gt;");
                cuerpoDelFallo = cuerpoDelFallo.Replace("<B >", string.Empty);
                cuerpoDelFallo = cuerpoDelFallo.Replace("<MI >", string.Empty);
                cuerpoDelFallo = cuerpoDelFallo.Replace(@"< ", "&lt; ");
                cuerpoDelFallo = cuerpoDelFallo.Replace(@"<=", "&lt;=");
                cuerpoDelFallo = cuerpoDelFallo.Replace(@"->", "-&gt;");
                cuerpoDelFallo = cuerpoDelFallo.Replace(@"<-", "&lt;-");
                cuerpoDelFallo = cuerpoDelFallo.Replace(@"<-", "&lt;-");
                cuerpoDelFallo = cuerpoDelFallo.Replace(@"<:", "&lt;:");
                cuerpoDelFallo = cuerpoDelFallo.Replace(@"<1", "&lt; 1");

                cuerpoDelFallo = cuerpoDelFallo.Replace(@"<Z", "&lt;Z");
                cuerpoDelFallo = cuerpoDelFallo.Replace(@"<AA", "&lt;AA");
                cuerpoDelFallo = cuerpoDelFallo.Replace(@"<p", "&lt;p");
                cuerpoDelFallo = cuerpoDelFallo.Replace(@"<X", "&lt;X");

                //<FD 20042287 (*)>
                int indexFD = 0;
                int lastIndexFD = 0;
                while (indexFD >= 0)
                {
                    indexFD = cuerpoDelFallo.IndexOf("<FD ", indexFD);
                    if (indexFD >= 0)
                    {
                        lastIndexFD = cuerpoDelFallo.IndexOf(">", indexFD);
                        string fdString = cuerpoDelFallo.Substring(indexFD, (lastIndexFD - indexFD) + 1);
                        cuerpoDelFallo = cuerpoDelFallo.Replace(fdString, string.Empty);
                    }
                }

                cuerpoDelFallo = Regex.Replace(cuerpoDelFallo, "(?<first><)(?<second>[0-9]*)(?<third>>)", "&#${second};");


                StringBuilder builder = new StringBuilder();

                // Analizo casos de este estilo ....LA PALABRA <FRAGATA> SE VISUALIZA CLARAMENTE, INDICANDO ADEMÁS...
                // en donde la palabra se destaca con < y >
                string parrafoOpen = "<Parrafo>";
                string parrafoClose = "</Parrafo>";

                string preText = string.Empty;
                string postText = string.Empty;

                int startIndex = cuerpoDelFallo.IndexOf(parrafoOpen, 0);
                int endIndex = cuerpoDelFallo.LastIndexOf(parrafoClose);

                if (startIndex > 0)
                {
                    preText = cuerpoDelFallo.Substring(0, startIndex);
                }

                if (endIndex >= 0)
                {
                    postText = cuerpoDelFallo.Substring(endIndex + parrafoClose.Length, cuerpoDelFallo.Length - (endIndex + parrafoClose.Length));
                }

                builder.Append(preText);
               
                int currentIndex = 0;
                while (currentIndex < cuerpoDelFallo.Length && currentIndex != -1)
                {
                    string text = GetTextBetweenTags(cuerpoDelFallo, parrafoOpen, parrafoClose, ref currentIndex);
                    builder.Append(parrafoOpen);

                    // Eliminar los tags de mas dentro del parrafo
                    text = EscapearTagsNoXML(text);

                    builder.Append(text);
                    builder.Append(parrafoClose);
                }

                builder.Append(postText);

                if (builder.Length > 0)
                {
                    cuerpoDelFallo = builder.ToString();
                }
            }
            else
            {
                cuerpoDelFallo = string.Empty;
            }            

            return cuerpoDelFallo;
        }

        private static string EscapearTagsNoXML(string text)
        {
            // Escapeo los tagas de este estilo:....LA PALABRA <FRAGATA> SE VISUALIZA CLARAMENTE, INDICANDO ADEMÁS...
            int startMayorIndex = 0;
            int startMenosIndex = 0;

            while (startMayorIndex >= 0 && startMayorIndex < text.Length && startMenosIndex >= 0)
            {
                startMayorIndex = text.IndexOf("<", startMenosIndex);
                if (startMayorIndex >= 0)
                {
                    startMenosIndex = text.IndexOf(">", startMayorIndex);
                    if (startMenosIndex >= 0)
                    {
                        string tagText = text.Substring(startMayorIndex + 1, startMenosIndex - (startMayorIndex + 1));
                        // Si el texto no contiene el tag de cierre tengo que escapearlos
                        if(!text.Contains("</" + tagText + ">"))
                        {
                            StringBuilder builder = new StringBuilder();
                            builder.Append(text.Substring(0, startMayorIndex));
                            builder.Append("&lt;");
                            builder.Append(tagText);
                            builder.Append("&gt;");
                            if (startMenosIndex + 1 < text.Length)
                            {
                                builder.Append(text.Substring(startMenosIndex + 1, text.Length - (startMenosIndex + 1)));
                            }

                            text = builder.ToString();
                        }
                    }
                }
            }

            return text;
        }

        private static string GetTextBetweenTags(string text, string parrafoOpen, string parrafoClose, ref int indexClose)
        {        
            int inicioParrafoOpen = 0;
            int inicioParrafoClose = 0;
            int finParrafoOpen = 0;
            int finParrafoClose = 0;
            string returnText = string.Empty;

            if (indexClose >= 0)
            {
                inicioParrafoOpen = text.IndexOf(parrafoOpen, indexClose);

                if (inicioParrafoOpen < 0)
                {
                    indexClose = -1;
                }

                if (inicioParrafoOpen >= 0 && indexClose >= 0)
                {
                    inicioParrafoClose = inicioParrafoOpen + parrafoOpen.Length - 1;
                    finParrafoOpen = text.IndexOf(parrafoClose, inicioParrafoClose);
                    if (finParrafoOpen >= 0)
                    {
                        finParrafoClose = finParrafoOpen + parrafoClose.Length;
                        indexClose = finParrafoClose;

                        returnText = text.Substring(inicioParrafoClose + 1, finParrafoOpen - inicioParrafoClose - 1);
                    }
                }
            }

            return returnText;
        }

        private List<LinkAp> GetCitasTipoDoctrina(PE_ONLINE_PRODUCCIONEntities ctxPeOnline, Guid guidDocumentoSae, int IdAP, XDocument xCuerpoFallo)
        {
            List<LinkAp> list = new List<LinkAp>();
            List<XElement> linksADoctrinaAnotada = (from node in xCuerpoFallo.Descendants()
                                                    where node.Name == "Cita" && node.Attribute("tipo").Value == "DOC"
                                                    select node).ToList();

            foreach (var linkADoctrinaNode in linksADoctrinaAnotada)
            {
                //<Cita tipo="DOC" ref="2506"/>
                string hreflink = linkADoctrinaNode.Attribute("ref").Value;
                string[] splitNorma = hreflink.Split('#');
                string[] splitArticulo = splitNorma[0].Split('_');
                int docFile = Convert.ToInt32(splitArticulo[0]);
                string articulo = string.Empty;
                if (splitNorma.Length == 2)
                {
                    articulo = splitNorma[1];
                }

                // Obtengo el id de la norma en función del archivo
                tDoctrinaSumario tdoctrinaRelacionada = (from docsumario in ctxPeOnline.tDoctrinaSumario
                                                         where docsumario.IdIdentLexis.HasValue
                                                         && docsumario.IdDDSumario == docFile
                                                         select docsumario).SingleOrDefault();

                if (tdoctrinaRelacionada != null)
                {
                    Guid doctrinaGuid = IdTranslationManager.GetGuidIdForApEntity(IdentityTranslationManager.tDoctrinaSumario, tdoctrinaRelacionada.IdDDSumario);
                    list.Add(new LinkAp()
                    {
                        GuidDocOrigen = guidDocumentoSae,
                        GuidDocDestino = doctrinaGuid,
                        IdApOrigen = IdAP,
                        IdApDestino = tdoctrinaRelacionada.IdDDSumario,
                        HrefLinkDoc = splitNorma[0],
                        HrefLinkAnchor = articulo,
                        HrefLinkValue = linkADoctrinaNode.Value,
                        xElementNode = linkADoctrinaNode
                    });
                }
            }

            return list;
        }

        private void CitasTipoImagen(Guid guidDocumentoSae, int IdAP, XDocument xCuerpoFallo)
        {
            List<XElement> parrafosConImagenElementList = (from node in xCuerpoFallo.Descendants()
                                                           where node.Name == "Parrafo"
                                                           && node.Value.Contains("INCLUDEPICTURE")
                                                           select node).ToList();

            foreach (XElement pictureNode in parrafosConImagenElementList)
            {
                int indexTop = pictureNode.Value.IndexOf(@"\\");
                int firstQuoteIndex = pictureNode.Value.IndexOf("\"");                
                int secondQuoteIndex = pictureNode.Value.IndexOf("\"", firstQuoteIndex + 1);

                if (secondQuoteIndex < 0)
                {
                    int tmpIndex = pictureNode.Value.IndexOf("“");
                    if (tmpIndex >= 0)
                    {
                        // Si la primera es cursiva
                        if (tmpIndex < firstQuoteIndex)
                        {
                            secondQuoteIndex = firstQuoteIndex;
                            firstQuoteIndex = tmpIndex;
                        }
                        else
                        {
                            // la segunda es cursiva
                            secondQuoteIndex = tmpIndex;                            
                        }
                    }
                }                

                string imagen = pictureNode.Value.Substring(firstQuoteIndex + 1, secondQuoteIndex - firstQuoteIndex - 1);

                // Testeo de eliminar los path de mas
                firstQuoteIndex = imagen.LastIndexOf("\\");
                if (firstQuoteIndex >= 0)
                {
                    imagen = imagen.Substring(firstQuoteIndex + 1);
                }
                else
                {
                    firstQuoteIndex = imagen.LastIndexOf("/");
                    imagen = imagen.Substring(firstQuoteIndex + 1);
                }

                Guid imagenGuid = IdTranslationManager.GetGuidIdForApEntity(IdentityTranslationManager.imagen, imagen);
                pictureNode.Value = string.Empty;
                XElement imagenElement = new XElement("imagen", imagenGuid.ToString());
                pictureNode.Add(imagenElement);
            }
        }

        private List<LinkAp> GetCitasTipoNotasAlPie(Guid guidDocumentoSae, int IdAP, XDocument xCuerpoFallo)
        {
            List<LinkAp> list = new List<LinkAp>();
            List<XElement> linksANotasAlPie = (from node in xCuerpoFallo.Descendants()
                                               where node.Name == "Cita" &&
                                               (node.Attribute("tipo").Value == "nota" || node.Attribute("tipo").Value == "detalle_nota")
                                               select node).ToList();

            foreach (var linkANota in linksANotasAlPie)
            {
                string hreflink = linkANota.Attribute("ref").Value;
                hreflink = hreflink.Replace("#", "");
                list.Add(new LinkAp()
                {
                    GuidDocOrigen = guidDocumentoSae,
                    GuidDocDestino = guidDocumentoSae,
                    IdApOrigen = IdAP,
                    IdApDestino = IdAP,
                    HrefLinkAnchor = hreflink,
                    HrefLinkValue = linkANota.Value,
                    xElementNode = linkANota
                });
            }

            return list;
        }

        private List<LinkAp> GetCitasTipoCun(PE_ONLINE_PRODUCCIONEntities ctxPeOnline, Guid guidDocumentoSae, int IdAP, XDocument xCuerpoFallo)
        {
            List<LinkAp> list = new List<LinkAp>();
            List<XElement> linksALegislacion = (from node in xCuerpoFallo.Descendants()
                                                where node.Name == "Cita" && node.Attribute("tipo").Value == "CUN"
                                                select node).ToList();

            foreach (var linkALegislacionNode in linksALegislacion)
            {
                //<Cita tipo="CUN" ref="L_NAC_LY_340.HTM#Art_236">236</Cita>
                string hreflink = linkALegislacionNode.Attribute("ref").Value;
                string[] splitNorma = hreflink.Split('#');
                string legisFile = splitNorma[0];
                string articulo = string.Empty;
                if (splitNorma.Length == 2)
                {
                    articulo = splitNorma[1];
                }

                // Obtengo el id de la norma en función del archivo
                tLegislacion tLegislacionRelacionada = (from legis in ctxPeOnline.tLegislacion
                                                        where legis.idIdentLexis.HasValue
                                                        && legis.arch_fisico == legisFile
                                                        select legis).SingleOrDefault();

                // Fix para el problema del cambio de version de documentos existentes
                //List<int> idsDeLaNorma = (from legis in ctxPeOnline.tLegislacion
                //                                        where legis.arch_fisico == legisFile
                //                                        orderby legis.id_legislacion descending
                //                                        select legis.id_legislacion).ToList();

                //// Ver si hay mas de uno y ver si esta en los mapeos
                //int id = IdTranslationManager.GetApIntFromList(IdentityTranslationManager.tLegislacion, idsDeLaNorma);

                //tLegislacion tLegislacionRelacionada = null;
                //if (id == 0)
                //{
                //        tLegislacionRelacionada = (from legis in ctxPeOnline.tLegislacion
                //                                            where legis.idIdentLexis.HasValue
                //                                            && legis.arch_fisico == legisFile
                //                                            select legis).SingleOrDefault();
                //}
                //else
                //{
                //    tLegislacionRelacionada = (from legis in ctxPeOnline.tLegislacion
                //                               where legis.id_legislacion == id
                //                               select legis).SingleOrDefault();
                //}
                // Fin fix

                if (tLegislacionRelacionada != null)
                {
                    Guid LegisGuid = IdTranslationManager.GetGuidIdForApEntity(IdentityTranslationManager.tLegislacion, tLegislacionRelacionada.idIdentLexis.Value);

                    list.Add(new LinkAp()
                    {
                        GuidDocOrigen = guidDocumentoSae,
                        GuidDocDestino = LegisGuid,
                        IdApOrigen = IdAP,
                        IdApDestino = tLegislacionRelacionada.id_legislacion,
                        HrefLinkDoc = legisFile,
                        HrefLinkAnchor = articulo,
                        HrefLinkValue = linkALegislacionNode.Value,
                        xElementNode = linkALegislacionNode
                    });
                }
                else
                {
                    list.Add(new LinkAp()
                    {
                        GuidDocOrigen = guidDocumentoSae,
                        IdApOrigen = IdAP,
                        HrefLinkDoc = legisFile,
                        HrefLinkAnchor = articulo,
                        HrefLinkValue = linkALegislacionNode.Value,
                        xElementNode = linkALegislacionNode,
                        EsDormido = true
                    });
                }
            }

            return list;
        }

        private void CitasParaListaDeLinks(List<LinkAp> list, bool usarVerTexto)
        {
            foreach (LinkAp link in list)
            {
                var linkALegislacionNode = link.xElementNode;

                bool mismoDoc = link.GuidDocDestino == link.GuidDocOrigen;

                if (mismoDoc)
                {
                    // No genero un cite sino un link comun
                    XElement newAncla = new XElement("a", string.Empty);

                    newAncla.Add(new XAttribute("href", string.Format("#{0}", link.HrefLinkAnchor)));
                    newAncla.Value = link.HrefLinkValue;
                    linkALegislacionNode.AddAfterSelf(newAncla);
                }

                if (!link.EsDormido)
                {
                    if (link.NoGenerarLink)
                    {
                        linkALegislacionNode.ReplaceWith(link.HrefLinkValue);
                    }
                    else
                    {
                        XElement newAncla = new XElement(citaStr, string.Empty);
                        DocumentLinking docLink = LinkManager.StoreLinkADocumento(link.GuidDocOrigen, link.GuidDocDestino, link.IdApOrigen, link.IdApDestino, link.HrefLinkAnchor, link.HrefLinkValue);
                        CreateLinkAttributes(newAncla, docLink, usarVerTexto);
                        linkALegislacionNode.ReplaceWith(newAncla);
                    }
                }
                else
                {
                    // es un link dormido                        
                    XElement newAncla = new XElement(citaStr, string.Empty);
                    DocumentLinking docLink = LinkManager.StoreLinkADocumentoDormido(link.GuidDocOrigen, link.IdApOrigen, link.HrefLinkAnchor, link.HrefLinkValue);
                    CreateLinkAttributes(newAncla, docLink, usarVerTexto);
                    linkALegislacionNode.ReplaceWith(newAncla);
                }
            }
        }

        private List<LinkAp> GetCitasTipoJurisprudencia(PE_ONLINE_PRODUCCIONEntities ctxPeOnline, Guid guidDocumentoSae, int IdAP, XDocument xCuerpoFallo)
        {
            List<LinkAp> list = new List<LinkAp>();
            List<XElement> linksAJurisprudencia = (from node in xCuerpoFallo.Descendants()
                                                   where node.Name == "Cita" && node.Attribute("tipo").Value == "JUR"
                                                   select node).ToList();

            foreach (var linkAJurisprudencia in linksAJurisprudencia)
            {
                //<Cita tipo="JUR" ref="4_1318.HTM"></Cita> // podrían tener un numeral
                string hreflink = linkAJurisprudencia.Attribute("ref").Value;
                string[] splitJurisprudencia = hreflink.Split('#');
                string legisFile = splitJurisprudencia[0];
                string articulo = string.Empty;
                if (splitJurisprudencia.Length == 2)
                {
                    articulo = splitJurisprudencia[1];
                }

                // Obtengo el id de la norma en función del archivo, puede ser un fallo o un sumario
                tJurisFallo jurisFallo = (from fallo in ctxPeOnline.tJurisFallo
                                          where fallo.IdIdentLexis.HasValue
                                          && fallo.ArchFisico == legisFile
                                          select fallo).SingleOrDefault();

                if (jurisFallo != null)
                {
                    CrearCitaParaFallo(list, guidDocumentoSae, IdAP, linkAJurisprudencia, articulo, jurisFallo);
                }
                else
                {
                    // analizo si es un sumario
                    tJurisSumario jurisSumario = (from fallo in ctxPeOnline.tJurisSumario
                                                  where fallo.IdIdentLexis.HasValue
                                                  && fallo.ArchFisico == legisFile
                                                  select fallo).SingleOrDefault();

                    if (jurisSumario != null)
                    {
                        // Segun nuevo pedido de Lemme si es un sumario, tengo que apuntar al fallo
                        tJurisSumarioCaratula jurisSumarioCaratula = jurisSumario.tJurisSumarioCaratula.First();
                        if (jurisSumarioCaratula != null)
                        {
                            tJurisFallo jurisFalloDelSumario = (from fallo in ctxPeOnline.tJurisFallo
                                                                where fallo.IdIdentLexis.HasValue
                                                                && fallo.ArchFisico == jurisSumarioCaratula.ArchTCompleto
                                                                select fallo).SingleOrDefault();
                            if (jurisFalloDelSumario != null)
                            {
                                CrearCitaParaFallo(list, guidDocumentoSae, IdAP, linkAJurisprudencia, articulo, jurisFalloDelSumario);
                            }
                            else
                            {
                                Guid sumarioGuid = IdTranslationManager.GetGuidIdForApEntity(IdentityTranslationManager.tJurisSumario, jurisSumario.IdJJSumario);

                                list.Add(new LinkAp()
                                {
                                    GuidDocOrigen = guidDocumentoSae,
                                    GuidDocDestino = sumarioGuid,
                                    IdApOrigen = IdAP,
                                    IdApDestino = jurisSumario.IdJJSumario,
                                    HrefLinkAnchor = articulo,
                                    HrefLinkValue = linkAJurisprudencia.Value,
                                    xElementNode = linkAJurisprudencia
                                });
                            }
                        }
                    }
                }
            }

            return list;
        }

        private void CrearCitaParaFallo(List<LinkAp> list, Guid guidDocumentoSae, int IdAP, XElement linkAJurisprudencia, string articulo, tJurisFallo jurisFallo)
        {
            Guid falloGuid = IdTranslationManager.GetGuidIdForApEntity(IdentityTranslationManager.tJurisFallo, jurisFallo.IdJJ);

            XElement newAncla = new XElement(citaStr, string.Empty);

            list.Add(new LinkAp()
            {
                GuidDocOrigen = guidDocumentoSae,
                GuidDocDestino = falloGuid,
                IdApOrigen = IdAP,
                IdApDestino = jurisFallo.IdJJ,
                HrefLinkAnchor = articulo,
                HrefLinkValue = linkAJurisprudencia.Value,
                xElementNode = linkAJurisprudencia
            });
        }

        private List<LinkAp> GetCitasTipoObraZZ(PE_ONLINE_PRODUCCIONEntities ctxPeOnline, Guid guidDocumentoSae, int IdAP, XDocument xCuerpoFallo)
        {
            List<LinkAp> list = new List<LinkAp>();
            List<XElement> linksAObras = (from node in xCuerpoFallo.Descendants()
                                          where node.Name == "Cita"
                                          && (node.Attribute("tipo").Value == "zzcita"
                                              || node.Attribute("tipo").Value == "ind")
                                          select node).ToList();

            foreach (var linkAObra in linksAObras)
            {
                //<Cita tipo="ind" ancla="JD_D100110020" ref="1001.htm">
                //<Cita tipo="zzcita" ref="1001.htm" ancla="JD_V_100110090"></Cita>

                int? idObra = null;
                string hreflink = string.Empty;
                if (linkAObra.Attribute("ref") != null)
                {
                    hreflink = linkAObra.Attribute("ref").Value;
                    // Obtengo el id de la obra
                    tObra obra = (from o in ctxPeOnline.tObra
                                  where o.ArchFisico == hreflink
                                  select o).SingleOrDefault();

                    if (obra != null)
                    {
                        idObra = obra.IdObra;
                    }
                }
                else
                {
                    // es a si mismo
                    tObra obra = (from o in ctxPeOnline.tObra
                                  where o.IdObra == IdAP
                                  select o).SingleOrDefault();

                    if (obra != null)
                    {
                        hreflink = obra.ArchFisico;

                        idObra = IdAP;
                    }
                }

                string articulo = linkAObra.Attribute("ancla").Value;

                if (idObra.HasValue)
                {
                    Guid obraGuid = IdTranslationManager.GetGuidIdForApEntity(IdentityTranslationManager.tObra, idObra.Value);

                    LinkAp linkAp = new LinkAp()
                     {
                         GuidDocOrigen = guidDocumentoSae,
                         GuidDocDestino = obraGuid,
                         IdApOrigen = IdAP,
                         IdApDestino = idObra.Value,
                         HrefLinkDoc = hreflink,
                         HrefLinkAnchor = articulo,
                         HrefLinkValue = linkAObra.Value,
                         xElementNode = linkAObra,
                         NoGenerarLink = true
                     };

                    list.Add(linkAp);
                }
                else
                {
                    // Pruebo con tObraCuerpo
                    List<tObraCuerpo> obraCuerpoList = (from o in ctxPeOnline.tObraCuerpo
                                                        where o.ArchFisico == hreflink
                                                        select o).ToList();

                    if (obraCuerpoList != null)
                    {
                        var obraCuerpo = obraCuerpoList.First();
                        //foreach (var obraCuerpo in obraCuerpoList)
                        //{
                            Guid obracuerpoGuid = IdTranslationManager.GetGuidIdForApEntity(IdentityTranslationManager.tObraCuerpo, obraCuerpo.IdCuerpo);
                            list.Add(new LinkAp()
                            {
                                GuidDocOrigen = guidDocumentoSae,
                                GuidDocDestino = obracuerpoGuid,
                                IdApOrigen = IdAP,
                                IdApDestino = obraCuerpo.IdCuerpo,
                                HrefLinkDoc = hreflink,
                                HrefLinkAnchor = articulo,
                                HrefLinkValue = linkAObra.Value,
                                xElementNode = linkAObra
                            });
                        //}
                    }
                }
            }

            return list;
        }

        private List<LinkAp> GetCitasJurisprudenciaAnotada(PE_ONLINE_PRODUCCIONEntities ctxPeOnline, Guid guidDocumentoSae, int IdAP, XDocument xCuerpoParrafos)
        {
            List<LinkAp> list = new List<LinkAp>();
            List<XElement> linksAJurisprudenciaAnotada = (from node in xCuerpoParrafos.Descendants()
                                                          where node.Name == "Cita" && node.Attribute("tipo").Value == "jj_anotada"
                                                          select node).ToList();

            foreach (var linkADoctrinaNode in linksAJurisprudenciaAnotada)
            {
                //<Cita tipo="CUN" ref="L_NAC_LY_340.HTM#Art_236">236</Cita>
                string hreflink = linkADoctrinaNode.Attribute("ref").Value;
                string[] splitNorma = hreflink.Split('#');
                string docFile = splitNorma[0];
                string articulo = string.Empty;
                if (splitNorma.Length == 2)
                {
                    articulo = splitNorma[1];
                }

                // Obtengo el id de la norma en función del archivo
                tDoctrinaSumario tdoctrinaRelacionada = (from docsumario in ctxPeOnline.tDoctrinaSumario
                                                         where docsumario.IdIdentLexis.HasValue
                                                         && docsumario.ArchFisico == docFile
                                                         select docsumario).SingleOrDefault();

                if (tdoctrinaRelacionada != null)
                {
                    Guid doctrinaGuid = IdTranslationManager.GetGuidIdForApEntity(IdentityTranslationManager.tDoctrinaSumario, tdoctrinaRelacionada.IdDDSumario);
                    list.Add(new LinkAp()
                    {
                        GuidDocOrigen = guidDocumentoSae,
                        GuidDocDestino = doctrinaGuid,
                        IdApOrigen = IdAP,
                        IdApDestino = tdoctrinaRelacionada.IdDDSumario,
                        HrefLinkDoc = docFile,
                        HrefLinkAnchor = articulo,
                        HrefLinkValue = linkADoctrinaNode.Value,
                        xElementNode = linkADoctrinaNode
                    });
                }
                else
                {
                    tJurisFallo jurisFallo = (from fallo in ctxPeOnline.tJurisFallo
                                              where fallo.IdIdentLexis.HasValue
                                              && fallo.ArchFisico == docFile
                                              select fallo).SingleOrDefault();

                    if (jurisFallo != null)
                    {
                        CrearCitaParaFallo(list, guidDocumentoSae, IdAP, linkADoctrinaNode, articulo, jurisFallo);
                    }
                }

            }

            return list;
        }

        private void CreateLinkAttributes(XElement ancla, DocumentLinking docLink, bool usarVerTexto)
        {
            string texto = usarVerTexto ? citaVerTexto : docLink.TextoMarcado;
            CreateLinkAttributes(ancla, docLink, texto);
        }

        protected string GetTextBetweenTags(string text, string startTag, string endTag)
        {
            int indexStartTag = text.IndexOf(startTag);
            int indexEndTag = text.IndexOf(endTag);
            return text.Substring(indexStartTag + startTag.Length, indexEndTag - (indexStartTag + startTag.Length));
        }

        private void CreateLinkAttributes(XElement ancla, DocumentLinking docLink, string supuestoVerTexto)
        {
            if (docLink != null)
            {
                if (docLink.GuidDocSaeDestino.HasValue)
                {
                    ancla.Add(new XAttribute("ref-guid-doc", docLink.GuidDocSaeDestino.Value.ToString()));
                }

                if (docLink.GuidAnclaDocDestino.HasValue)
                {
                    ancla.Add(new XAttribute("ref-guid-cite", docLink.GuidAnclaDocDestino.Value.ToString()));
                }

                ancla.Add(new XAttribute("guid", docLink.Id.ToString()));

                ancla.Value = supuestoVerTexto;
            }
        }
    }
}
